package com.tuzhi.filestore.websocket.server;

import cn.hutool.core.collection.ConcurrentHashSet;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.tuzhi.filestore.websocket.enums.MsgTypeEnum;
import com.tuzhi.filestore.websocket.vo.MessageVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 功能说明：
 *
 * @author abu
 * @version 1.1.0
 * @date 2023/2/21
 */
@ServerEndpoint(value = "/fsws/{userId}")
@Service
@Slf4j
public class FileStoreWebSocketServer {
    private static BillAppService billAppService;

    @Autowired
    public void setBillAppService(BillAppService billAppService) {
        this.billAppService = billAppService;
    }

    /**
     * 当前在线连接数
     */
    private static AtomicInteger onlineCount = new AtomicInteger(0);

    /**
     * 用来存放每个客户端对应的 WebSocketServer 对象
     */
    private static ConcurrentHashMap<String, FileStoreWebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 用来存放前端模拟打开报价专用websocket专用服务客户端对应
     */
    private static ConcurrentHashSet<String> wsSet4App = new ConcurrentHashSet<>();


    public static ConcurrentHashMap<String, FileStoreWebSocketServer> getWebSocketMap() {
        return webSocketMap;
    }

    public static ConcurrentHashSet<String> getWsSet4App() {
        return wsSet4App;
    }

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 接收 userId
     */
    private String userId = "";

    Set<Long> ListeningOrder = new HashSet<>();

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            webSocketMap.put(userId, this);
        } else {
            webSocketMap.put(userId, this);
            addOnlineCount();
        }
        log.info("用户连接:" + userId + ",当前在线人数为:" + getOnlineCount());
        try {
            sendMessage("连接成功！");
        } catch (IOException e) {
            log.error("用户:" + userId + ",网络异常!!!!!!");
        }
    }


    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(userId)) {
            webSocketMap.remove(userId);
            subOnlineCount();
        }
        log.info("用户退出:" + userId + ",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
//        log.info("用户消息:" + userId + ",报文:" + message);
        if (StringUtils.isEmpty(message)) {
            log.warn("提交的消息为空：{}", this.userId);
            return;
        }

        try {
           /* MessageVo<List<Long>> messageVo = JSONObject.parseObject(message, new TypeReference<MessageVo<List<Long>>>() {
            });*/
            MessageVo messageVo = JSONObject.parseObject(message, MessageVo.class);
            MsgTypeEnum msgType = messageVo.getType();
            switch (msgType) {
                case ping:
                    sendMessage("pong");
                    break;
                case listeningOrder:
                    MessageVo<List<Long>> messageVo2 = JSONObject.parseObject(message, new TypeReference<MessageVo<List<Long>>>() {
                    });
                    if (CollectionUtils.isNotEmpty(messageVo2.getData())) {
                        this.ListeningOrder.addAll(messageVo2.getData());
                    }
                    log.info("userId:{},加入监听modelId:{}", userId, messageVo2.getData());
                    break;
                case listeningAutoCheck:
                    wsSet4App.add(userId);
                    log.info("{} ,加入前端模拟打开报价专用websocket专用服务客户端", userId);
                    break;
                case autoCheckResult:
                    //   客户端返回检测结果   ,修改模型状态
                    billAppService.updateFileModel(messageVo);
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            log.error("收到消息处理异常 err:userId-{},message:{},err={}", userId, message, ExceptionUtils.getStackTrace(e));
        }
    }

    /**
     * 发生错误时调用
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        //log.error("用户错误:" + this.userId + ",原因:" + error.getMessage());
        log.error("userId:{},异常：{}", this.userId, ExceptionUtils.getStackTrace(error));
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    public static synchronized AtomicInteger getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        FileStoreWebSocketServer.onlineCount.getAndIncrement();
    }

    public static synchronized void subOnlineCount() {
        FileStoreWebSocketServer.onlineCount.getAndDecrement();
    }

    public String getUserId() {
        return userId;
    }

}
